package monitor

import (
	"cloud_worm/worm/client/monitor/processevent"
	"context"
	"fmt"
	"cloud_worm/worm/config"
	"strings"
	"github.com/golang/glog"
	"errors"
	"io/ioutil"
	"cloud_worm/util/proto/ujson"
	"sync"
	"cloud_worm/worm/client/monitor/monitorlog"
	"cloud_worm/util/ufile"
)

var cmdMutex   sync.Mutex
var cmdMonitor *processevent.ProcessMonitor

// StartCmdMonitor cmd monitor
func StartCmdMonitor(localIP string) error {
	cmdMutex.Lock()
	defer cmdMutex.Unlock()

	if cmdMonitor != nil {
		return errors.New("cmd monitor had started")
	}

	if strings.Contains(config.CfgInst.RunMode, "dev") {
		ctxCmd, cancelCmd := context.WithCancel(context.Background())

		// 测试环境，命令监控写日志，不写kafka
		ps := processevent.NewProcessMonitor(localIP, nil, monitorlog.MonLogFd, cancelCmd)
		if ps == nil {
			err := fmt.Errorf("new process monitor failed")
			PushMonitorErrInfo(err)
			return err
		}
		ps.Loop(ctxCmd)

		cmdMonitor = ps
	} else if strings.HasPrefix(localIP, "10.70.") == false && strings.HasPrefix(localIP, "10.13.") == false {
		// 线上环境，但是不包括"10.13."和"10.90"
		ctxCmd, cancelCmd := context.WithCancel(context.Background())

		// 命令监控，写日志、写kafka
		p, err := producerPool.Get(CmdTopic)
		if err != nil {
			e := fmt.Errorf("get topic'%s' producer error", CmdTopic)
			PushMonitorErrInfo(e)
			return e
		}
		ps := processevent.NewProcessMonitor(localIP, p, monitorlog.MonLogFd, cancelCmd)
		if ps == nil {
			producerPool.Put(CmdTopic)
			e := fmt.Errorf("new process monitor failed")
			PushMonitorErrInfo(e)
			return e
		}
		ps.Loop(ctxCmd)

		cmdMonitor = ps
	}

	if err := processevent.WhiteListInstance.LoadWhiteList(); err != nil {
		glog.Errorf("LoadWhiteList: %s", err.Error())
		PushMonitorErrInfo(err)
	}
	glog.Info("start cmd monitor loop.....")
	return nil
}

func StopCmdMonitor()  {
	cmdMutex.Lock()
	defer cmdMutex.Unlock()

	if cmdMonitor == nil {
		return
	}

	cmdMonitor.Close()
	producerPool.Put(CmdTopic)
	cmdMonitor = nil
}

func init()  {
	cmdMonitor = nil
}

func UpdateCmdWhiteKey(fileURL string, md5 string) error {
	cmdMutex.Lock()
	defer cmdMutex.Unlock()

	if cmdMonitor == nil {
		return nil
	}

	destFile := "./var/" + ujson.CmdRuleFile
	oldMd5 := ufile.GetFileMd5(destFile)
	if oldMd5 == md5 {
		return nil
	}

	if err := ufile.DownloadFile(fileURL, destFile); err != nil {
		glog.Error(fmt.Sprintf("download file'%s' error: %s", ujson.CmdRuleFile, err.Error()))
		PushMonitorErrInfo(err)
		return err
	}

	data, err := ioutil.ReadFile(destFile)
	if err != nil {
		return err
	}
	if strings.Contains(string(data), ujson.Page404NotFound) {
		err := errors.New(fmt.Sprintf("url: %s, 404 page not found", fileURL))
		PushMonitorErrInfo(err)
		return err
	}
	tmp := strings.Split(string(data), "\n")

	self := make([]string, 0, len(tmp))
	parent := make([]string, 0, len(tmp))
	for _, item := range tmp {
		l := strings.TrimSpace(item)
		if l == "" {
			continue
		}
		ln := strings.Split(l, "|")
		if len(ln) != 2 {
			continue
		}

		// 1--parent; 2--self
		if strings.TrimSpace(ln[0]) == "1" {
			parent = append(parent, strings.TrimSpace(ln[1]))
		} else if strings.TrimSpace(ln[0]) == "2" {
			self = append(self, strings.TrimSpace(ln[1]))
		} else {
			continue
		}
	}

	processevent.WhiteListInstance.ParentList.Lock()
	processevent.WhiteListInstance.ParentList.List = parent
	glog.Infof("parent list: %v", processevent.WhiteListInstance.ParentList.List)
	processevent.WhiteListInstance.ParentList.Unlock()

	processevent.WhiteListInstance.SelfList.Lock()
	processevent.WhiteListInstance.SelfList.List = self
	glog.Infof("self list: %v", processevent.WhiteListInstance.SelfList.List)
	processevent.WhiteListInstance.SelfList.Unlock()
	return nil
}